package com.zengdada.authority.config.security.intercept;

import com.zengdada.authority.model.AppUser;
import com.zengdada.authority.service.AppRoleAuthorityService;
import com.zengdada.authority.service.AppUserAuthorityService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.WebAuthenticationDetails;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;
import org.springframework.stereotype.Service;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import java.util.*;

/**
 * 权限管理类
 */
@Service
public class AuthorityUtil {

    @Autowired
    @Qualifier("appRoleAuthorityServiceImpl")
    private AppRoleAuthorityService roleService;

    @Autowired
    @Qualifier("appUserAuthorityServiceImpl")
    private AppUserAuthorityService userService;

    @Autowired
    private ServletContext servletContext;

    /**
     * 清理用户 = 注销
     */
    public void clearSecurityContext() {
        SecurityContextHolder.clearContext();
    }

    /**
     * 初始化用户权限 登录
     *
     * @param request
     * @param user
     */
    public void initAuthority(HttpServletRequest request, AppUser user) {
        if (user == null || StringUtils.isBlank(user.getId()) || request == null)
            throw new RuntimeException("不能对空的用户或者请求初始化权限");
        Set<GrantedAuthority> authSet = new HashSet<>();
        List<Map<String, Object>> roles = roleService.getRoleByUser(user);
        roles.forEach(role -> authSet.add(new SimpleGrantedAuthority(String.valueOf(role.get("code")))));
        authSet.add(new SimpleGrantedAuthority("ROLE_AUTHORITY_USER")); //赋予普通用户权限
//        if (user.getAccountshared() != null && (user.getAccountshared() & 4) == 4)
//            authSet.add(new SimpleGrantedAuthority("ROLE_SUPER_ADMINISTRATOR"));
//        authSet.add(new SimpleGrantedAuthority(roleService.selectByPrimaryKey(user.getRoleId()).getRoleValue()));
        //根据userDetails构建新的Authentication,这里使用了
        //PreAuthenticatedAuthenticationToken当然可以用其他token,如UsernamePasswordAuthenticationToken
        PreAuthenticatedAuthenticationToken authentication =
                new PreAuthenticatedAuthenticationToken(user, servletContext.getAttribute("security_power_version"), authSet);

        //设置authentication中details
        authentication.setDetails(new WebAuthenticationDetails(request));
        //存放authentication到SecurityContextHolder
        SecurityContextHolder.getContext().setAuthentication(authentication);
    }

    /**
     * 更新权限资源缓存
     *
     * @return
     */
    public Authentication updateAuthority() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (!(authentication instanceof PreAuthenticatedAuthenticationToken)) throw new RuntimeException("用户尚未登陆！！");
        PreAuthenticatedAuthenticationToken preAuthenticatedAuthenticationToken = (PreAuthenticatedAuthenticationToken) authentication;
        Set<GrantedAuthority> authSet = new HashSet<>();
        authSet.add(new SimpleGrantedAuthority("ROLE_AUTHORITY_USER")); //赋予普通用户权限
        AppUser user = (AppUser) preAuthenticatedAuthenticationToken.getPrincipal();
        user = userService.selectById(user.getId());
        List<Map<String, Object>> roles = roleService.getRoleByUser(user);
        roles.forEach(role -> authSet.add(new SimpleGrantedAuthority(String.valueOf(role.get("code")))));
//        if (user.getAccountshared() != null && (user.getAccountshared() & 4) == 4)
//            authSet.add(new SimpleGrantedAuthority("ROLE_SUPER_ADMINISTRATOR"));
        PreAuthenticatedAuthenticationToken authenticationNew =
                new PreAuthenticatedAuthenticationToken(preAuthenticatedAuthenticationToken.getPrincipal(), servletContext.getAttribute("security_power_version"), authSet);
        authenticationNew.setDetails(preAuthenticatedAuthenticationToken.getDetails());
        SecurityContextHolder.getContext().setAuthentication(authenticationNew);
        return authenticationNew;
    }

    /**
     * 获取当前权限列
     *
     * @return Collection<GrantedAuthority>
     * 未登录时会抛出异常  RuntimeException("用户尚未登陆！！")
     */
    public Collection<GrantedAuthority> getGrantedAuthority() {
        return getGrantedAuthority(false);
    }

    /**
     * 获取当前权限列 可控制异常
     *
     * @param noExceptions false 产生异常，true 不产生异常 返回null
     * @return Collection<GrantedAuthority>
     */
    public Collection<GrantedAuthority> getGrantedAuthority(boolean noExceptions) {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (!(authentication instanceof PreAuthenticatedAuthenticationToken))
            if (noExceptions) return null;
            else throw new RuntimeException("用户尚未登陆！！");
        PreAuthenticatedAuthenticationToken preAuthenticatedAuthenticationToken = (PreAuthenticatedAuthenticationToken) authentication;
        return preAuthenticatedAuthenticationToken.getAuthorities();
    }

    /**
     * 获取当前登录用户
     *
     * @return AppUser
     * 未登录时会抛出异常  RuntimeException("用户尚未登陆！！")
     */
    public AppUser getLoginUser() {
        return getLoginUser(false);
    }

    /**
     * 更新当前登录用户信息
     *
     * @return AppUser
     */
    public void updateLoginUser() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (!(authentication instanceof PreAuthenticatedAuthenticationToken)) return;
        PreAuthenticatedAuthenticationToken preAuthenticatedAuthenticationToken = (PreAuthenticatedAuthenticationToken) authentication;
        AppUser user = (AppUser) preAuthenticatedAuthenticationToken.getPrincipal();
        AppUser newUser = userService.selectById(user.getId());
        PreAuthenticatedAuthenticationToken newAuthentication =
                new PreAuthenticatedAuthenticationToken(newUser, servletContext.getAttribute("security_power_version"), preAuthenticatedAuthenticationToken.getAuthorities());
        //设置authentication中details
        newAuthentication.setDetails(preAuthenticatedAuthenticationToken.getDetails());
        //存放authentication到SecurityContextHolder
        SecurityContextHolder.getContext().setAuthentication(newAuthentication);
    }

    /**
     * 获取当前登录用户 可控制异常
     *
     * @param noExceptions false 产生异常，true 不产生异常 返回null
     * @return
     */
    public AppUser getLoginUser(boolean noExceptions) {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (!(authentication instanceof PreAuthenticatedAuthenticationToken))
            if (noExceptions) return null;
            else throw new RuntimeException("用户尚未登陆！！");
        PreAuthenticatedAuthenticationToken preAuthenticatedAuthenticationToken = (PreAuthenticatedAuthenticationToken) authentication;
        return (AppUser) preAuthenticatedAuthenticationToken.getPrincipal();
    }

    /**
     * 获取当前登录用户 可控制异常  静态方法 可以不创建实例
     * @param noExceptions
     * @return
     */
    public static AppUser getLoginUser1(boolean noExceptions) {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (!(authentication instanceof PreAuthenticatedAuthenticationToken))
            if (noExceptions) return null;
            else throw new RuntimeException("用户尚未登陆！！");
        PreAuthenticatedAuthenticationToken preAuthenticatedAuthenticationToken = (PreAuthenticatedAuthenticationToken) authentication;
        return (AppUser) preAuthenticatedAuthenticationToken.getPrincipal();
    }

    /**
     * 判断当前用户是否拥有指定权限
     *
     * @param role 权限名
     * @return boolean
     * 未登录时会抛出异常  RuntimeException("用户尚未登陆！！")
     */
    public boolean hasAuthority(String role) {
        return getGrantedAuthority().contains(new SimpleGrantedAuthority(role));
    }

    /**
     * 判断当前用户是否拥有指定权限 可控制异常
     *
     * @param role         权限名
     * @param noExceptions false 产生异常，true 不产生异常 返回null
     * @return boolean
     */
    public boolean hasAuthority(String role, boolean noExceptions) {
        Collection<GrantedAuthority> grantedAuthority = getGrantedAuthority(noExceptions);
        if (grantedAuthority == null) return false;
        return grantedAuthority.contains(new SimpleGrantedAuthority(role));
    }

    /**
     * 判断是否拥有超级管理权限
     *
     * @return boolean
     * 未登录时会抛出异常  RuntimeException("用户尚未登陆！！")
     */
    public boolean isSuperAdministrator() {
        return hasAuthority("ROLE_SUPER_ADMINISTRATOR");
    }

    /**
     * 判断是否拥有超级管理权限 可控制异常
     *
     * @param noExceptions false 产生异常，true 不产生异常 返回null
     * @return
     */
    public boolean isSuperAdministrator(boolean noExceptions) {
        return hasAuthority("ROLE_SUPER_ADMINISTRATOR", noExceptions);
    }
}
